package json.gson;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.reflect.TypeToken;
import json.BaseBean;
import json.DateFormat;
import json.User;
import org.junit.Test;

import java.util.List;

/**
 * @describe: gson的使用
 *      Gson是谷歌官方推出的支持 JSON -- Java Object相互转换的 Java序列化/反序列化库
 * @author: houkai
 */
public class GsonDemo {

    /**
     * 数据类型生成与解析
     */
    @Test
    public void aTest() {
        //基本数据
        Gson gson = new Gson();
        int i = gson.fromJson("1", int.class);
        System.out.println(gson.toJson(i));
        //数组
        String jsonss = "[\"aa\",\"bb\",\"cc\"]";
        String[] ss = gson.fromJson(jsonss, String[].class);

        //包装数据
        String s = gson.fromJson("str", String.class);
        System.out.println(gson.toJson(s));

        //自定义对象
        User user = User.init();
        String userStr = gson.toJson(user);
        user = gson.fromJson(userStr, User.class);
        System.out.println(user.toString());
    }

    /**
     * 泛型
     */
    @Test
    public void bTest() {
        Gson gson = new Gson();
        String jsonss = "[\"1\",\"2\",\"3\"]";
        List<String> list = gson.fromJson(jsonss, new TypeToken<List<String>>() {
        }.getType());
        System.out.println(list);

        jsonss = "{\"code\":\"0\",\"data\":[\"1\",\"2\",\"3\"]}";
        BaseBean baseBean = gson.fromJson(jsonss, new TypeToken<BaseBean<List<String>>>() {
        }.getType());
        System.out.println(baseBean.toString());
    }

    /**
     * 时间格式化, 对象中包含事件时的转换，需要指定DateFormat
     */
    @Test
    public void cTest() {
        Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
        String dateFormatStr = "{\"d\":\"2019-09-09 09:09:09\"}";
        DateFormat dateFormat = gson.fromJson(dateFormatStr, DateFormat.class);
        System.out.println(dateFormat);
    }

    /**
     * 使用 @SerializedName 注解对对象序列化时进行重命名
     */
    @Test
    public void dTest(){
        String str1 = "{\"name\":\"zha\"}";
        String str2 = "{\"nm\":\"zha\"}";
        String str3 = "{\"xingming\":\"zha\"}";

        Gson gson = new Gson();
        SerialReName serialReName = gson.fromJson(str1, SerialReName.class);
        gson.fromJson(str2, SerialReName.class);
        gson.fromJson(str3, SerialReName.class);
        System.out.println(serialReName.toString());
    }

    /**
     * 显示null的值
     */
    @Test
    public void eTest(){
        User user = new User("小明",true,16,null);
        Gson gson = new GsonBuilder()
                .serializeNulls()
                .create();

        String userStr = gson.toJson(user);
        System.out.println(userStr);
    }

    /*
     * 其它序列化控制
     * 1.new GsonBuilder()
     * .disableInnerClassSerialization()   //内部类不序列化
     * .disableHtmlEscaping()	    //html标签不转义
     * .create();
     */

    /*
     *  注解 @Expose的使用 ： 控制对象中的参数是否需要序列化和反序列化，其中：
     *      @Expose(deserialize = true,serialize = true) //序列化和反序列化都都生效
     *      @Expose(deserialize = true,serialize = false) //反序列化时生效
     *      @Expose(deserialize = false,serialize = true) //序列化时生效
     *      @Expose(deserialize = false,serialize = false) //和不写一样
     *
     *      @Expose(deserialize = false,serialize = false)
     *      private String homeAddress;// 和不写一样，不管是序列化还是反序列化都和正常使用一样
     *      此时，Gson必须通过如下的方式进行实例化：
     *      Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
     */

    /*
     * 注解：@Since(int i) 和 @Until(int i)的用法
     *      @Since(int i)和@Until(int i)是一种版本控制，当版本号大于Since的值时，会解析出该字段，否则不会解析出来，当版本号小于Until的时会解析出来该字段，否则不会。看代码：
     *  public class User {
     *      @Since（3） private String name;
     *      private boolean sex;
     *      private int age;
     *      @Until（5） private String homeAddress;
     *  }
     * 解析代码：
     * Gson gson = new GsonBuilder().setVersion(int version).create();
     * 结果分析：
     * 若version<3 则解析结果为：{"homeAddress":“中国xxxxxxxx”,"age":16,"sex":true}
     * 若version>=3并且version<5 则解析结果为：{"name":"小明","homeAddress":“中国xxxxxxxx”,"age":16,"sex":true}
     * 若version>=5 则解析结果为：{"name":"小明","age":16,"sex":true}
     * 其实范围可以概括为，Until之前Since之后；
     *
     */

    /*
     *通过访问修饰符控制序列化和反序列化
     *  访问修饰符包括：public、private、protected、static 、final等，注意：static 会自动被排除。
     *  通过代码解释：
     * public class User {
     *  private String name;
     *  public boolean sex;
     *  static int age;
     *  final String homeAddress;
     * }
     *
     * Gson gson = new GsonBuilder().excludeFieldsWithModifiers(Modifier.FINAL, Modifier.PRIVATE).create();
     * System.out.println(gson.toJson(user));
     * 结果：{"sex":true}
     */


    /*
     *TypeAdapter的使用，TypeAdapter 是Gson的一个抽象类，用于接管某种类型的序列化和反序列化过程。
     * public abstract class TypeAdapter<T> {
     *      public abstract void write(JsonWriter out, T value) throws IOException;
     *      public abstract T read(JsonReader in) throws IOException;
     * }
     * 使用示例基本类型：
     * Gson gson = new GsonBuilder().registerTypeAdapter(Integer.class, new TypeAdapter<Integer>() {
     *      @Override public void write(JsonWriter out, Integer value) throws IOException {
     *          out.value(String.valueOf(value));
     *      }
     *
     *      @Override public Integer read(JsonReader in) throws IOException {
     *          try {
     *              return Integer.parseInt(in.nextString());
     *          } catch (NumberFormatException e) {
     *            return -1;
     *          }
     *      }
     * }).create();
     *
     * 使用示例自定义类型：
     * Gson gson = new GsonBuilder().registerTypeAdapter(User.class, new UserTypeAdapter()).create();
     * UserTypeAdapter的定义：
     * public class UserTypeAdapter extends TypeAdapter<User> {
     *      @Override public void write(JsonWriter out, User value) throws IOException {
     *          out.beginObject();
     *          out.name("name").value(value.name);
     *          out.name("age").value(value.age);
     *          out.name("sex").value(value.sex);
     *          out.name("homeAdress").value(value.homeAdress);
     *          out.endObject();
     *      }
     *      @Override public User read(JsonReader in) throws IOException {
     *          User user = new User();
     *          in.beginObject();
     *          while (in.hasNext()) {
     *            switch (in.nextName()) {
     *              case "name": user.name = in.nextString(); break;
     *              case "age": user.age = in.nextInt(); break;
     *              case "home":
     *              case "home_address":
     *              case "homeAddress": user.homeAddress = in.nextString(); break
     *            }
     *          }
     *          in.endObject();
     *          return user;
     *      }
     * }
     */

     /*
     *@JsonAdapter注解的使用
     *  该注解必须配合TypeAdpater，JsonSerializer或JsonDeserializer中的一个使用，其中是不需要
     * Gson gson = new GsonBuilder().registerTypeAdapter(User.class, new UserTypeAdapter()).create();
     * 直接Gson gson = new Gson();既可以将类似UserTypeAdapter的序列化和反序列化规则用于注解的类。
     * 使用示例：
     *  @JsonAdapter(UserTypeAdapter.class)
     *  public class User {
     *      private String name;//序列化时生效
     *      private boolean sex; private int age;
     *      private String homeAddress;// 和不写一样，不管是序列化还是反序列化都和正常使用一样
     *  }
     */

    /**
     * Json 操作
     *  JsonObject
     *  JsonArray
     *  JsonElement
     */
    @Test
    public void fTest(){
        JsonObject object = new JsonObject();
        object.addProperty("a", "av");

        JsonArray jsonArray = new JsonArray();
        jsonArray.add("1");
        jsonArray.add("2");
        object.add("je", jsonArray);
        System.out.println(object);
    }
}
